import { Input, Select, Tag } from "antd";
import { SearchSelectResult, SelectOption, TypeOptions } from "../../utils/types";
import { CSSProperties, ChangeEvent, ReactNode, useEffect, useRef, useState } from "react";
import { getChangeEventValue, getUuid, isEmpty } from "../../utils";
import CustomPopover from "../popover/CustomPopover";
import CustomSelect from "./CustomSelect";
import useReSize from "../../hooks/useResize";

interface Props {
    options: SelectOption[],
    selectPopoverWidth: number
    value?: string
    style: CSSProperties
    onChange?: (e: SearchSelectResult) => any
    placeholder?: string
    maxLength?: number,
    allowClear?: boolean
    nodeRender?: (option: SelectOption, tempInputValue: string) => ReactNode
    showSelectWhenMatch?: boolean
}

const SearchSelect = (props: Props, ref: any) => {
    const {
        options,
        value = null,
        style,
        onChange,
        placeholder,
        maxLength,
        selectPopoverWidth = 500,
        allowClear = true,
        showSelectWhenMatch = false,
        nodeRender
    } = props;

    const delayTimer = useRef(null);
    const containerRef = useRef(null);
    const customPopoverRef = useRef(null);
    const selectContainerRef = useRef(null);
    const searchSelectInputRef = useRef(null);

    const containerResize = useReSize(containerRef)

    const tempInputValueRef = useRef<string>('');

    const [tempInputValue, setTempInputValue] = useState<string>('');

    const [filteredOptions, setFilteredOptions] = useState<SelectOption[]>([]);

    const [customPopoverPosition, setCustomPopoverPosition] = useState({ clientX: 0, clientY: 0 });

    const tempSelectedOption = useRef<any>(null);

    useEffect(() => {
        measureSelectPosition();
        return () => {
            delayTimer.current && clearTimeout(delayTimer.current);
        }
    }, [containerResize])

    useEffect(() => {
        let newValue = "";
        if (value && typeof value == 'object') {
            //@ts-ignore
            newValue = value.value;
        } else {
            newValue = value;
        }
        if(newValue !== tempInputValue){
            setTempInputValue(newValue);
        }
    }, [value])

    const measureSelectPosition = () => {
        const clientRect = selectContainerRef.current.getBoundingClientRect();
        const { top, left } = clientRect;
        setCustomPopoverPosition({ clientX: left, clientY: top + 44 })
    }

    const renderSearchSelectOption = (option: SelectOption) => {
        const tempSearchValue = tempInputValue;
        const { label } = option;
        try {
            if (isEmpty(tempSearchValue)) {
                return label;
            }
            let reg = new RegExp(tempSearchValue);
            let str = label.split(reg);
            let txt = [];
            if (str.length === 0 || str.length === 1) {
                return label
            }
            if (str.length > 0) {
                txt.push(<span key={'index-1' + ''}>{str[0]}</span>);
            }
            txt.push(<span key={'index-2' + ''} style={{ color: '#f5222d' }}>{tempSearchValue}</span>);
            if (str.length > 1) {
                txt.push(<span key={'index-3'}>{str[1]}</span>);
            }
            if (str.length >= 3) {
                for (let i = 2; i < str.length; i++) {
                    txt.push(<span key={'index' + i + '1'} style={{ color: '#f5222d' }}>{tempSearchValue}</span>);
                    txt.push(<span key={'index' + i + '2'}>{str[i]}</span>);
                }
            }
            return txt;
        } catch (e) {
            return label;
        }
    }

    useEffect(() => {
        if (tempInputValue != null || tempInputValue != undefined) {
            let _filteredOptions = [];
            options.forEach(option => {
                if (option.label && option.label.includes(tempInputValue.toString())) {
                    _filteredOptions.push(option)
                }
            })
            setFilteredOptions([..._filteredOptions])
        }
    }, [tempInputValue, options])

    const onSelectInputTextChange = (e: ChangeEvent<HTMLInputElement>) => {
        if (!getChangeEventValue(e) && e.type !== 'change') {
            onChange({
                value: "",
                option: null
            })
        }
        setTempInputValue(getChangeEventValue(e));
        tempInputValueRef.current = getChangeEventValue(e);
        tempSelectedOption.current = null;
        let _filteredOptions = [];
        options.forEach(option => {
            if (option.label && option.label.includes(tempInputValue.toString())) {
                _filteredOptions.push(option)
            }
        })
        if(_filteredOptions.length){
            customPopoverRef.current?.show();
        }
    }

    const onSelectInputFocus = () => {
        searchSelectInputRef.current.select();
        if (!showSelectWhenMatch) {
            customPopoverRef.current?.show();
        }
    }

    const finshiEdit = () => {
        if (!isEmpty(tempInputValueRef.current)) {
            onChange({
                value: tempInputValueRef.current,
                option: tempSelectedOption.current
            })
        }
    };

    const onSelectInputBlur = () => {
        finshiEdit();
    };

    const onSelect = (value: string, option: SelectOption) => {
        setTempInputValue(value);
        tempInputValueRef.current = value;
        const findTopic = options.find(ele => {
            return ele.value == option.value;
        })
        tempSelectedOption.current = findTopic;
        finshiEdit();
    }

    const onSelectPopoverShow = () => {
    }

    const onSelectPopoverHide = () => {
        searchSelectInputRef.current.blur();
        finshiEdit();
    }

    const renderSelectOption = (option: SelectOption, index: number) => {
        if (nodeRender) {
            return nodeRender(option, tempInputValue)
        }
        return (
            <div className="flex-row">
                {
                    option.tag ?
                        <Tag color={'blue'}>{option.tag}</Tag>
                        :
                        null
                }
                {renderSearchSelectOption(option)}
            </div>
        )
    }

    return (
        <div
            ref={containerRef}
            className="search-select-container"
            style={style}
        >
            <div
                ref={selectContainerRef}
                className="search-select-content"
            >
                <Input
                    ref={searchSelectInputRef}
                    className="search-select-content-input"
                    placeholder={placeholder ? placeholder : '请选择或输入'}
                    value={tempInputValue}
                    onChange={onSelectInputTextChange}
                    allowClear={allowClear}
                    onFocus={onSelectInputFocus}
                    onBlur={onSelectInputBlur}
                />
            </div>
            {
                filteredOptions.length && !(filteredOptions.length == 1 && filteredOptions[0].label == tempInputValue) ?
                    <CustomPopover
                        ref={customPopoverRef}
                        clientX={customPopoverPosition.clientX}
                        clientY={customPopoverPosition.clientY}
                        onShow={onSelectPopoverShow}
                        onHide={onSelectPopoverHide}
                        contentRender={(props) => (
                            <CustomSelect
                                {...props}
                                width={selectPopoverWidth}
                                value={value}
                                maxHeight={420}
                                onSelect={onSelect}
                                selectTarget={'label'}
                                emptyText={'暂无匹配结果'}
                                customOptionRender={renderSelectOption}
                                options={filteredOptions && filteredOptions.length >= 0 ? filteredOptions : options}
                            />
                        )}
                    />
                    :
                    null
            }
        </div>
    )
}

export default SearchSelect;